package com.xhwl.logistics.strategy.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xhwl.common.dto.cent.device.DeviceDTO;
import com.xhwl.common.enums.CategoryEnum;
import com.xhwl.common.enums.CodeEnum;
import com.xhwl.common.exception.BusinessException;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.device.Device;
import com.xhwl.common.pojo.cent.vehicle.VehcArea;
import com.xhwl.common.query.cent.device.DevicePageQuery;
import com.xhwl.common.query.cent.vehicle.AreaQuery;
import com.xhwl.common.vo.cent.vehicle.CarVO;
import com.xhwl.logistics.bo.VehicleAccessRecordSecondBO;
import com.xhwl.logistics.bo.VehicleCarRecordInParkingLotBO;
import com.xhwl.logistics.bo.VehicleCarportBO;
import com.xhwl.logistics.bo.cent.VehicleIntegratedConfigBO;
import com.xhwl.logistics.bo.input.QueryVehicleAccessRecordRealtimeBO;
import com.xhwl.logistics.bo.input.QueryVehicleCarRecordInParkingLotBO;
import com.xhwl.logistics.bo.input.QueryVehicleCarportBO;
import com.xhwl.logistics.bo.manipulate.VehicleSyncBO;
import com.xhwl.logistics.converter.mapstruct.CentDeviceConverter;
import com.xhwl.logistics.dao.mapper.IVehicleParkingLotInfoMapper;
import com.xhwl.logistics.dto.query.DeviceControlDTO;
import com.xhwl.logistics.entity.VehicleParkingLot;
import com.xhwl.logistics.entity.VehiclePassage;
import com.xhwl.logistics.po.VehicleParkingLotInfoPO;
import com.xhwl.logistics.po.VehicleParkingLotPO;
import com.xhwl.logistics.service.cent.IDeviceService;
import com.xhwl.logistics.service.cent.QueryDeviceSecondService;
import com.xhwl.logistics.service.impl.VehcAreaServiceImpl;
import com.xhwl.logistics.service.impl.VehicleParkingLotServiceImpl;
import com.xhwl.logistics.service.impl.VehiclePassageServiceImpl;
import com.xhwl.logistics.service.impl.http.FuShiHttpServiceImpl;
import com.xhwl.logistics.strategy.IVehicleParkingLotHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Optionals;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
//@Service
public class VehicleParkingLotFuShiHandlerImpl implements IVehicleParkingLotHandler {

    @Autowired
    private FuShiHttpServiceImpl fuShiHttpService;

    @Autowired
    private IVehicleParkingLotInfoMapper vehicleParkingLotInfoMapper;

    @Autowired
    private VehicleParkingLotServiceImpl vehicleParkingLotService;

    @Autowired
    private VehcAreaServiceImpl vehcAreaService;

    @Autowired
    private VehiclePassageServiceImpl vehiclePassageService;

    @Autowired
    private IDeviceService deviceService;

    @Autowired
    private CentDeviceConverter centDeviceConverter;

    @Autowired
    private QueryDeviceSecondService queryDeviceSecondService;

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void sync(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, VehicleSyncBO vehicleSyncBO) {
        log.info("FuShi sync start!");
        log.info("vehicleIntegratedConfigBO: " + vehicleIntegratedConfigBO);
        Integer projectId = vehicleSyncBO.getProjectId();

        Optional<VehicleParkingLotInfoPO> optionalVehicleParkingLotInfoPO = vehicleParkingLotInfoMapper.queryParkingLotInfoByProjectId(projectId);

        Optional<VehicleParkingLotPO> optionalVehicleParkingLotPO;

        /*******************同步车场**************************/
        if (optionalVehicleParkingLotInfoPO.isPresent()) {
            VehicleParkingLotInfoPO vehicleParkingLotInfoPO = optionalVehicleParkingLotInfoPO.get();
            List<VehicleParkingLotPO> vehicleParkingLotPOList = vehicleParkingLotInfoPO.getVehicleParkingLotPOList();
            Assert.isTrue(vehicleParkingLotPOList.size() == 1, "项目下，对于富士厂商的车场只能有一个");

            VehicleParkingLotPO vehicleParkingLotPO = vehicleParkingLotPOList.get(0);
            optionalVehicleParkingLotPO = Optional.of(vehicleParkingLotPO);
        } else {
            optionalVehicleParkingLotPO = Optional.empty();
        }

        VehicleParkingLot tempVehicleParkingLot = new VehicleParkingLot();
        //车场信息同步不考虑删除车场的情况，考虑新增，更新（一个车场车位数）
        VehicleParkingLot vehcParkingLot = fuShiHttpService.getParkingLotInfo(vehicleIntegratedConfigBO.getVehicleParkingInfoBO(), projectId);
        Optionals.ifPresentOrElse(
                optionalVehicleParkingLotPO,
                vehicleParkingLotPO -> {
                    vehcParkingLot.setId(optionalVehicleParkingLotPO.get().getId());
                    vehicleParkingLotService.updateById(vehcParkingLot);
                    tempVehicleParkingLot.setId(vehcParkingLot.getId());
                },
                () -> {
                    vehicleParkingLotService.save(vehcParkingLot);
                    tempVehicleParkingLot.setId(vehcParkingLot.getId());
                }
        );

        /*******************同步默认区域(由于富士不存在区域概念)**************************/
        AreaQuery areaQuery = new AreaQuery();
        areaQuery.setParkingLotId(tempVehicleParkingLot.getId());
        VehcArea vehcArea;
        List<VehcArea> vehcAreas = vehcAreaService.list(areaQuery);
        if(vehcAreas == null || vehcAreas.size() == 0) {
            VehcArea area = new VehcArea();
            area.setParkingLotId(tempVehicleParkingLot.getId());
            area.setCarSpotNum(vehcParkingLot.getCarportTotalNumber());
            area.setName("总区域");
            area.setThirdAreaId(tempVehicleParkingLot.getId().toString());
            vehcAreaService.save(area);
            vehcArea = area;
        }else {
            vehcArea = vehcAreas.get(0);
        }



        /*******************同步通道**************************/

        List<VehiclePassage> vehiclePassageList = vehiclePassageService.list(conditionPassage(projectId));

        List<String> passageThirdIdList = vehiclePassageList.stream().map(vehiclePassage -> vehiclePassage.getThirdPassageId()).collect(Collectors.toList());

        List<VehiclePassage> vehcPassageList = fuShiHttpService.getPassageList(vehicleIntegratedConfigBO.getVehicleParkingInfoBO(), projectId);

        List<String> vendorPassageThirdIdList = vehcPassageList.stream()
                .map(vehcPassage -> String.valueOf(vehcPassage.getThirdPassageId()))
                .collect(Collectors.toList());

        Map<String, VehiclePassage> mapForVehiclePassage = vehiclePassageList.stream()
                .collect(Collectors.toMap(vehiclePassage -> String.valueOf(vehiclePassage.getThirdPassageId()), Function.identity()));

        Map<String, VehiclePassage> mapForVendorPassage = vehcPassageList.stream()
                .collect(Collectors.toMap(vehiclePassage -> String.valueOf(vehiclePassage.getThirdPassageId()), Function.identity()));

        //通道信息同步不考虑删除通道的情况，考虑新增，更新（通道的名称）
        List<String> addForPassage = ListUtils.subtract(vendorPassageThirdIdList, passageThirdIdList);
        List<String> updateForPassage = ListUtils.intersection(passageThirdIdList, vendorPassageThirdIdList);

        if (!addForPassage.isEmpty()) {
            List<VehiclePassage> add = addForPassage.stream()
                    .map(passageThirdId -> {
                        VehiclePassage vehiclePassage = mapForVendorPassage.get(passageThirdId);
                        vehiclePassage.setParkingLotId(tempVehicleParkingLot.getId());
                        vehiclePassage.setAreaId(vehcArea.getId());
                        return vehiclePassage;
                    })
                    .collect(Collectors.toList());
            vehiclePassageService.saveBatch(add);
        }

        if (!updateForPassage.isEmpty()) {
            List<VehiclePassage> update = updateForPassage.stream()
                    .map(passageThirdId -> {
                        VehiclePassage vehiclePassage = mapForVehiclePassage.get(passageThirdId);
                        vehiclePassage.setParkingLotId(tempVehicleParkingLot.getId());
                        vehiclePassage.setAreaId(vehcArea.getId());
                        return vehiclePassage;
                    })
                    .collect(Collectors.toList());

            vehiclePassageService.updateBatchById(update);
        }

        log.info("FuShi sync end!");
    }

    @Override
    public void syncDevice(VehicleIntegratedConfigBO vehicleIntegratedConfigBO) {

        DevicePageQuery devicePageQuery = new DevicePageQuery();
        devicePageQuery.setProjectId(vehicleIntegratedConfigBO.getVehicleSystemInfoBO().getProjectId());
        devicePageQuery.setCategoryId(CategoryEnum.YARD_GATE.getId());

        List<DeviceDTO> deviceDTOList = deviceService.listDevice(null, devicePageQuery);

        List<Device> fuShiDeviceList = fuShiHttpService.getParkingLotDevice(vehicleIntegratedConfigBO);

        Map<String, Device> mapForVendorDevice = fuShiDeviceList.stream()
                .collect(Collectors.toMap(device -> String.valueOf(device.getThirdDeviceId()), Function.identity()));

        List<String> fuShiDeviceIdList = fuShiDeviceList.stream().map(device -> String.valueOf(device.getThirdDeviceId())).collect(Collectors.toList());
        List<String> ownerDeviceIdList = deviceDTOList.stream().map(device -> String.valueOf(device.getThirdDeviceId())).collect(Collectors.toList());

        //通道信息同步不考虑删除通道的情况，考虑新增，更新（通道的名称）
        List<String> addForDevice = ListUtils.subtract(fuShiDeviceIdList, ownerDeviceIdList);
        List<String> updateForDevice = ListUtils.intersection(ownerDeviceIdList, fuShiDeviceIdList);

        if (!addForDevice.isEmpty()) {
            List<Device> add = addForDevice.stream().map(threeDeviceId->{
                return mapForVendorDevice.get(threeDeviceId) ;
            }).collect(Collectors.toList());
            ResultJson<?> resultJson = deviceService.batchSave(null, add);
            centDeviceResponseHandle(resultJson, "feign调用设备中台的批量保存出错");
        }
        if (!updateForDevice.isEmpty()) {
            List<DeviceDTO> update = updateForDevice.stream().map(threeDeviceId->{
                return centDeviceConverter.device2DeviceDTO(mapForVendorDevice.get(threeDeviceId));
            }).collect(Collectors.toList());
            ResultJson<?> resultJson = deviceService.batchUpdate(null, update);
            centDeviceResponseHandle(resultJson, "feign调用设备中台的批量更新出错");
        }
    }

    @Override
    public VehicleCarportBO queryCarport(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, QueryVehicleCarportBO queryVehicleCarportBO) {
        fuShiHttpService.getParkingLotInfo(vehicleIntegratedConfigBO.getVehicleParkingInfoBO(), queryVehicleCarportBO.getProjectId());
        VehicleCarportBO vehicleCarportBO = new VehicleCarportBO();
        vehicleCarportBO.setFreeNumber(0);
        vehicleCarportBO.setTotalNumber(0);
        return vehicleCarportBO;
    }

    @Override
    public VehicleCarRecordInParkingLotBO queryCarRecordInParkingLot(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, QueryVehicleCarRecordInParkingLotBO queryVehicleCarRecordInParkingLotBO) {
        return null;
    }

    @Override
    public List<VehicleAccessRecordSecondBO> queryAccessRecordRealtime(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, QueryVehicleAccessRecordRealtimeBO queryVehicleAccessRecordRealtimeBO) {
        return null;
    }

    @Override
    public void statisticsToBi(VehicleIntegratedConfigBO vehicleIntegratedConfigBO) {

    }

    @Override
    public void openDevice(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, DeviceControlDTO deviceControlDTO) {

    }

    @Override
    public void closeDevice(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, DeviceControlDTO deviceControlDTO) {

    }

    @Override
    public void allOpenDevice(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, DeviceControlDTO deviceControlDTO) {

    }

    @Override
    public String reserverSpace(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, CarVO carVO) {
        return null;
    }

    @Override
    public void cancelReserve(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, String orderNo) {

    }

    @Override
    public String getCarBillInfo(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, String plateNumber) {
        return null;
    }

//    @Override
//    public void syncDevice(VehicleIntegratedConfigBO vehicleIntegratedConfigBO) {
//        log.info("FuShi sync device start!");
//        log.info("vehicleIntegratedConfigBO: " + vehicleIntegratedConfigBO);
//
//        VehicleSystemInfoBO vehicleSystemInfoBO = vehicleIntegratedConfigBO.getVehicleSystemInfoBO();
//        Integer projectId = vehicleSystemInfoBO.getProjectId();
//        Integer productId = vehicleSystemInfoBO.getProductId();
//        Integer productCategoryId = vehicleSystemInfoBO.getProductCategoryId();
//
//        List<Device> deviceListFromFuShi = fuShiHttpService.getParkingLotDevice(vehicleIntegratedConfigBO.getVehicleParkingInfoBO());
//
//        List<DeviceBO> deviceListFromCentDevice = queryDeviceSecondService.queryDevicesByProjectId(projectId);
//        Map<String, Integer> temp = deviceListFromCentDevice.stream().collect(Collectors.toMap(DeviceBO::getNumber, DeviceBO::getId));
//
//        //获取通道信息，将设备与通道进行关联
//        List<VehiclePassage> vehiclePassageList = vehiclePassageService.list(new LambdaQueryWrapper<VehiclePassage>().eq(VehiclePassage::getProjectId, vehicleIntegratedConfigBO.getVehicleSystemInfoBO().getProjectId()));
//        Map<String, VehiclePassage> mapForPassage = vehiclePassageList.stream().collect(Collectors.toMap(s -> s.getRemark(), Function.identity()));
//        List<String> ipFromPassage = vehiclePassageList.stream().map(s -> s.getRemark()).collect(Collectors.toList());
//
//        List<DeviceBO> add = new ArrayList<>();
//        List<DeviceBO> update = new ArrayList<>();
//        deviceListFromFuShi.forEach(parkingLotDeviceInfoFuShiDTO -> {
//            Optionals.ifPresentOrElse(
//                    Optional.ofNullable(temp.get(parkingLotDeviceInfoFuShiDTO.getIotDeviceId())),
//                    id -> {
//                        //将主相机的ip与之关联通道进行关联，方便获取设备地址
//                        String ip = ipFromPassage.stream().filter(s -> {
//                            if (StringUtils.equals(s, parkingLotDeviceInfoFuShiDTO.getDeviceIp())) {
//                                return true;
//                            } else {
//                                return false;
//                            }
//                        }).findAny().orElse(null);
//                        if(ip!=null){
//                            ip=mapForPassage.get(ip).getPassageName();
//                        }
//                        DeviceBO deviceBO = centDeviceConverter.toDeviceBOByFuShi(id, parkingLotDeviceInfoFuShiDTO, projectId, productId, productCategoryId,ip);
//                        update.add(deviceBO);
//                    },
//                    () -> {
//                        String ip = ipFromPassage.stream().filter(s -> {
//                            if (StringUtils.equals(s, parkingLotDeviceInfoFuShiDTO.getDeviceIp())) {
//                                return true;
//                            } else {
//                                return false;
//                            }
//                        }).findAny().orElse(null);
//                        if(ip!=null){
//                            ip=mapForPassage.get(ip).getPassageName();
//                        }
//                        DeviceBO deviceBO = centDeviceConverter.toDeviceBOByFuShi(parkingLotDeviceInfoFuShiDTO, projectId, productId, productCategoryId,ip);
//                        add.add(deviceBO);
//                    });
//        });
//
//        if (!add.isEmpty()) {
//            queryDeviceSecondService.addDevices(add);
//        }
//
//        if (!update.isEmpty()) {
//            queryDeviceSecondService.updateDevices(update);
//            queryDeviceSecondService.updateDeviceStatus(update);
//        }
//
//        log.info("FuShi sync device end!");
//    }

//    @Override
//    public VehicleCarRecordInParkingLotBO queryCarRecordInParkingLot(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, QueryVehicleCarRecordInParkingLotBO queryVehicleCarRecordInParkingLotBO) {
//        Integer projectId = queryVehicleCarRecordInParkingLotBO.getProjectId();
//        String parkingLotName = queryVehicleCarRecordInParkingLotBO.getParkingLotName();
//
//        VehicleParkingLotSecondBO vehicleParkingLotSecondBO = vehicleParkingLotService.queryParkingLot(projectId, parkingLotName);
//
//        FreeSpaceNumberExtFuShiDTO freeSpaceNumberExtFuShiDTO = fuShiHttpService.queryFreeSpaceNumberExt(vehicleIntegratedConfigBO, new QueryFreeSpaceNumberFuShiDTO());
//        List<CarOccupiedInfoFuShiDTO> carOccupiedInfoFuShiDTOList = Optional.ofNullable(freeSpaceNumberExtFuShiDTO.getCarOccupiedInfo()).orElse(new ArrayList<>());
//
//        return vehicleCarConverter.toVehicleCarRecordInParkingLotBOByFuShi(carOccupiedInfoFuShiDTOList, vehicleParkingLotSecondBO.getParkingLotName());
//    }

//    @Override
//    public void openDevice(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, DeviceControlDTO deviceControlDTO){
//
//    }

    private Wrapper<VehiclePassage> conditionPassage(Integer projectId) {
        LambdaQueryWrapper<VehiclePassage> vehiclePassageLambdaQueryWrapper = new LambdaQueryWrapper<>();
        return vehiclePassageLambdaQueryWrapper.eq(VehiclePassage::getProjectId, projectId);
    }

    private void centDeviceResponseHandle(ResultJson<?> resultJson, String message) {
        if (!(resultJson.getState() && resultJson.getCode().equals(CodeEnum.SUCCESS.code))) {
            throw new BusinessException(message);
        }
    }
}
